package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xuecheng.base.exception.ResponseResult;
import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.content.checkutils.CheckInsertResultUtil;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.mapper.CourseMarketMapper;
import com.xuecheng.content.mapper.TeachplanMediaMapper;
import com.xuecheng.content.model.dto.*;
import com.xuecheng.content.model.po.*;
import com.xuecheng.content.mapper.TeachplanMapper;
import com.xuecheng.content.service.TeachplanService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import com.xuecheng.content.model.po.CourseBase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.xml.ws.Holder;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 课程计划 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class TeachplanServiceImpl extends ServiceImpl<TeachplanMapper, Teachplan> implements TeachplanService {

    @Autowired
    private TeachplanMapper teachplanMapper;

    @Autowired
    private CourseBaseMapper courseBaseMapper;
    @Autowired
    private CourseMarketMapper courseMarketMapper;
    @Autowired
    private TeachplanMediaMapper teachplanMediaMapper;
    /**
     * 查询课程计划树形结构数据
     *
     * @param courseId 课程ID，用于查询指定课程的树形结构
     * @return 树形结构的课程计划DTO列表（包含嵌套子节点）
     */
    @Override
    public List<TeachplanTreeNodeDto> selectTeachTreeNodes(Long courseId) {
//        校验
        List<TeachplanTreeNode> list = teachplanMapper.selectCourseTree(courseId);
        List<TeachplanTreeNodeDto> treeNodeDtos = new ArrayList<>();
        Map<Long, List<TeachplanTreeNode>> parentIdMap = list.stream().collect(Collectors.groupingBy(TeachplanTreeNode::getParentid));          // 按父ID分组，便于查找子节点
        List<TeachplanTreeNode> rootNodes = parentIdMap.getOrDefault(0L, Collections.emptyList());                  // 获取所有根节点（parentid=0）
        for (TeachplanTreeNode rootNode : rootNodes) {                          // 转换为DTO并构建子树
            TeachplanTreeNodeDto rootDto = buildTree(rootNode, parentIdMap);
            treeNodeDtos.add(rootDto);
        }
//        拼装返回
        return treeNodeDtos;
    }

    /**
     * 递归构建树形结构DTO
     *
     * @param node         当前处理的树节点（可能是任意层级的节点）
     * @param parentIdMap  按父ID分组的节点映射表（Key: 父ID, Value: 子节点列表）
     * @return 包含完整子树结构的课程计划DTO对象
     *
     * 工作流程：
     * 1. 将当前节点转换为DTO
     * 2. 查找当前节点的所有直接子节点
     * 3. 递归处理每个子节点生成子树
     * 4. 将子树挂载到当前节点DTO
     */
    private TeachplanTreeNodeDto buildTree(TeachplanTreeNode node, Map<Long, List<TeachplanTreeNode>> parentIdMap) {
        TeachplanTreeNodeDto dto = convertToDto(node);                          // 转换为DTO
        List<TeachplanTreeNode> children = parentIdMap.getOrDefault(node.getTeachplanId(), Collections.emptyList());           // 获取当前(父节点,二级节点)节点的子节点
        List<TeachplanTreeNodeDto> childDtos = children.stream().map(child -> buildTree(child, parentIdMap)).collect(Collectors.toList());                      // 递归构建子树
        dto.setTeachPlanTreeNodes(childDtos);                                           // 将单节点放入dto
        return dto;
    }

    /**
     * 将实体对象转换为DTO对象
     *
     * @param node 原始课程计划节点实体
     * @return 转换后的课程计划DTO对象
     *
     * 转换规则：
     * 1. 使用BeanUtils复制同名基础字段
     * 2. 若存在媒体资源ID（teachplanMediaId），则构建TeachplanMedia对象
     *    - 需手动映射 mediaId/mediaFilename 字段
     *    - 因为实体类中媒体资源字段是平级存储，而DTO中是嵌套对象
     */
    private TeachplanTreeNodeDto convertToDto(TeachplanTreeNode node) {
        TeachplanTreeNodeDto dto = new TeachplanTreeNodeDto();
        BeanUtils.copyProperties(node, dto);                            // 复制基础属性
        dto.setId(node.getTeachplanId());

        // 处理媒体资源
        if (node.getTeachplanMediaId() != null) {
            TeachplanMedia media = new TeachplanMedia();
            media.setId(node.getTeachplanMediaId());
            media.setMediaId(node.getMediaId());
            media.setMediaFilename(node.getMediaFilename());
            // 其他字段根据实际情况设置
            dto.setTeachplanMedia(media);
        }
        return dto;
    }
    //    新增章节
    @Override
    public TeachplanDto createChapter(SaveTeachplanDto saveTeachplanDto) {
        Teachplan teachplanInsertOrUpdate = new Teachplan();
        BeanUtils.copyProperties(saveTeachplanDto,teachplanInsertOrUpdate);
        TeachplanDto resultTeachplanDto = new TeachplanDto();

        if(saveTeachplanDto.getId()==null){
            teachplanInsertOrUpdate = createChapterInit( teachplanInsertOrUpdate);
            CheckInsertResultUtil.check(teachplanMapper.insert(teachplanInsertOrUpdate),()->new XueChengPlusException("新增章节失败"));
        }else {
            teachplanInsertOrUpdate.setChangeDate(LocalDateTime.now());
            CheckInsertResultUtil.check(teachplanMapper.updateNotEmptyFields(teachplanInsertOrUpdate),()->new XueChengPlusException("更新章节失败"));
        }
        BeanUtils.copyProperties(teachplanInsertOrUpdate,resultTeachplanDto);
        return resultTeachplanDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult deleteChapter(Long teachplanId) {
//       删除大章节
        Teachplan selectTeachplan = teachplanMapper.selectById(teachplanId);
//        如果大章节下面还有小章节 无法删除  没有小章节才可以删除
        List<Teachplan> slave = teachplanMapper.selectList(new LambdaQueryWrapper<Teachplan>().eq(Teachplan::getParentid, teachplanId));
        if(slave.isEmpty()){
            teachplanMapper.deleteById(teachplanId);        //删除当前节点
            teachplanMediaMapper.deleteById(teachplanId);   //删除节点对应资源
            return new ResponseResult("200");
        }
        return new ResponseResult("120409","课程信息还有子节点信息,无法操作");
    }



    // 交换排序值（使用Optional处理）
    private void swapOrderby(Teachplan node1, Teachplan node2) {
        // 交换值
        Integer temp = node1.getOrderby();
        node1.setOrderby(node2.getOrderby());
        node2.setOrderby(temp);
        // 批量更新
        teachplanMapper.updateById(node1);
        teachplanMapper.updateById(node2);
    }
    @Override
    public void teachplanMoveDownOrUp(Long teachplanId, String type) {
        Optional<Teachplan> currentOpt = Optional.ofNullable(teachplanMapper.selectById(teachplanId));                       // 获取当前节点
        Function<Teachplan, Optional<Teachplan>> neighborFinder = current -> getAdjacentNode(current, type);                 // 获取相邻节点函数

        // 执行交换
        currentOpt.flatMap(neighborFinder).ifPresent(neighbor -> {
                    Teachplan current = currentOpt.get();
                    swapOrderby(current, neighbor);
                });
    }
    // 查询课程计划对应的资源文件信息
    @Override
    public TeachplanAndTeachplanMediaDto teachplanAndTeachplanMedia(Long teachId) {
        Teachplan selectTeachplan = teachplanMapper.selectById(teachId);        // 查询对应的课程计划
        TeachplanMedia selectTeachplanMedia = teachplanMediaMapper.selectOne(new LambdaQueryWrapper<TeachplanMedia>().eq(TeachplanMedia::getTeachplanId, teachId));// 查询课程计划对应的文件信息
        TeachplanAndTeachplanMediaDto teachplanAndTeachplanMediaDto = new TeachplanAndTeachplanMediaDto();
        Optional.ofNullable(selectTeachplan).ifPresent(item ->{BeanUtils.copyProperties(selectTeachplan,teachplanAndTeachplanMediaDto);});
        TeachplanMediaDto teachplanMediaDto = new TeachplanMediaDto();
        Optional.ofNullable(selectTeachplanMedia).ifPresent(list -> {BeanUtils.copyProperties(list, teachplanMediaDto);});
        teachplanAndTeachplanMediaDto.setNewTeachplanMediaDto(teachplanMediaDto);
        return teachplanAndTeachplanMediaDto;
    }

    //    更新数据库记录
    public TeachplanAndTeachplanMediaDto teachplanMediaUpdateFile(MediaFilesDto mediaFilesDto) {
        // 1. 重命名变量明确意图
        Long teachplanId = mediaFilesDto.getTeacherId();
        Teachplan teachplan = teachplanMapper.selectById(teachplanId);
        CheckInsertResultUtil.checkExist(teachplan,()-> new XueChengPlusException("课程计划不存在"));

        // 2. 避免重复查询课程信息
        CourseBase courseBase = courseBaseMapper.selectById(teachplan.getCourseId());
        CourseMarket courseMarket = courseMarketMapper.selectById(teachplan.getCourseId());
        CheckInsertResultUtil.checkExist(courseBase,()-> new XueChengPlusException("课程信息不完整"));


        // 3. 抽离公共设置逻辑
        updateTeachplanFields(teachplan, mediaFilesDto, courseBase, courseMarket);

        // 4. 使用更精确的查询条件
        TeachplanMedia teachplanMedia = teachplanMediaMapper.selectOne(new LambdaQueryWrapper<TeachplanMedia>().eq(TeachplanMedia::getTeachplanId, teachplanId)
                .eq(TeachplanMedia::getCourseId, teachplan.getCourseId()));

        TeachplanAndTeachplanMediaDto result = new TeachplanAndTeachplanMediaDto();
        BeanUtils.copyProperties(teachplan, result);

        if (teachplanMedia != null) {
            // 5. 记录修改前的媒体信息
            TeachplanMediaDto oldMediaDto = new TeachplanMediaDto();
            BeanUtils.copyProperties(teachplanMedia, oldMediaDto);

            // 6. 更新媒体信息
            updateMediaFields(teachplanMedia, mediaFilesDto);
            CheckInsertResultUtil.checkExist(teachplanMediaMapper.updateById(teachplanMedia),()-> new XueChengPlusException("课程计划媒体信息更新失败"));

            // 7. 构建返回结果
            TeachplanMediaDto newMediaDto = new TeachplanMediaDto();
            BeanUtils.copyProperties(teachplanMedia, newMediaDto);
            result.setOldTeachplanMediaDto(oldMediaDto);
            result.setNewTeachplanMediaDto(newMediaDto);
        } else {
            // 8. 创建新媒体记录
            TeachplanMedia newMedia = createNewMedia(teachplan, mediaFilesDto);
            CheckInsertResultUtil.checkExist(teachplanMediaMapper.insert(newMedia),()-> new XueChengPlusException("课程计划媒体信息新增失败"));
            // 9. 单一职责原则返回结果
            BeanUtils.copyProperties(newMedia, result);
        }

        return result;
    }

    @Override
    public List<Teachplan> selectListByCourseId(String courseId) {
        return teachplanMapper.selectList(new LambdaQueryWrapper<Teachplan>().eq(Teachplan::getCourseId,courseId));
    }

    // 抽离的公共方法
    private void updateTeachplanFields(Teachplan teachplan, MediaFilesDto dto, CourseBase courseBase, CourseMarket courseMarket) {
        teachplan.setMediaType(dto.getFileType());
        teachplan.setStartTime(courseBase.getCreateDate());
        Optional.ofNullable(dto.getTimelength()).ifPresent(item->{teachplan.setTimelength(dto.getTimelength());});  // 存放视频时间长度
        // 使用安全的空值处理
        int validDays = Optional.ofNullable(courseMarket.getValidDays()).orElse(0);
        teachplan.setEndTime(courseBase.getCreateDate().plusDays(validDays));
        teachplan.setDescription(dto.getRemark());
        teachplan.setChangeDate(LocalDateTime.now()); // 修改时间始终更新

        CheckInsertResultUtil.checkExist(teachplanMapper.updateById(teachplan),()->new XueChengPlusException("课程计划更新失败"));
    }

    private void updateMediaFields(TeachplanMedia media, MediaFilesDto dto) {
        media.setMediaId(dto.getId() != null ? String.valueOf(dto.getId()) : dto.getFileId());
        media.setMediaFilename(dto.getFilename());
    }

    private TeachplanMedia createNewMedia(Teachplan teachplan, MediaFilesDto dto) {
        TeachplanMedia media = new TeachplanMedia();
        media.setTeachplanId(teachplan.getId());
        media.setCourseId(teachplan.getCourseId());
        media.setMediaId(dto.getId() != null ? String.valueOf(dto.getId()) : dto.getFileId());
        media.setMediaFilename(dto.getFilename());
        media.setCreateDate(LocalDateTime.now()); // 新增时设置创建时间
        return media;
    }






    private Optional<Teachplan> getAdjacentNode(Teachplan current, String type) {
        // 定义条件构建函数
        Function<LambdaQueryWrapper<Teachplan>, LambdaQueryWrapper<Teachplan>> conditionBuilder;

        if ("moveup".equalsIgnoreCase(type)) {
            conditionBuilder = w -> w.lt(Teachplan::getOrderby, current.getOrderby())
                    .orderByDesc(Teachplan::getOrderby);
        } else if ("movedown".equalsIgnoreCase(type)) {
            conditionBuilder = w -> w.gt(Teachplan::getOrderby, current.getOrderby())
                    .orderByAsc(Teachplan::getOrderby);
        } else {
            return Optional.empty();
        }

        // 构建查询
        LambdaQueryWrapper<Teachplan> wrapper = new LambdaQueryWrapper<Teachplan>().eq(Teachplan::getParentid, current.getParentid()).eq(Teachplan::getCourseId, current.getCourseId());
        return Optional.of(wrapper).map(conditionBuilder).map(w -> w.last("LIMIT 1")).map(teachplanMapper::selectOne);
    }


    /**
     * 获取教学计划的数量
     * @return 教学计划的数量
     */
    public Teachplan createChapterInit(Teachplan teachplan){
        CourseBase selectCourseBase = courseBaseMapper.selectById(teachplan.getCourseId());
        CourseMarket selectCourseMarket = courseMarketMapper.selectById(teachplan.getCourseId());
        //        获取orderBy最大的一条记录
        Teachplan selectTeachplanLast = teachplanMapper.selectOne(new LambdaQueryWrapper<Teachplan>().eq(Teachplan::getCourseId, teachplan.getCourseId()).eq(Teachplan::getParentid, teachplan.getParentid()).eq(Teachplan::getGrade, teachplan.getGrade()).orderByDesc(Teachplan::getOrderby).last("LIMIT 1"));
        teachplan.setStartTime(selectCourseBase.getCreateDate());
        teachplan.setEndTime(selectCourseBase.getCreateDate().plusDays(selectCourseMarket.getValidDays()));
        teachplan.setCreateDate(LocalDateTime.now());
        Integer orderBy = Optional.ofNullable(selectTeachplanLast).map(Teachplan::getOrderby).map(order -> order + 1).orElse(0);
        teachplan.setOrderby(orderBy);
        return teachplan;
    }
}
